#include "StdAfx.h"
#include "SignaledObjectEvent.h"

using namespace Adaptive::Foundation;

/*--------------------------------------------------------------------------------
 * Constructor / Dispose / Destructor Methods
 *------------------------------------------------------------------------------*/
#pragma region Constructor / Dispose / Destructor Methods
// Initializes a new instance of the class.
SignaledObjectEvent::SignaledObjectEvent() : AiObjectBase()
{
	_eventHandle = NULL;
	_executeThread = false;
	_asyncWaitThread = nullptr;
	_eventHandle = ::CreateEvent(NULL, false, false, NULL);
}
// Initializes a new instance of the class.
SignaledObjectEvent::SignaledObjectEvent(String^ name) : AiObjectBase()
{
	CString wideName = name;

	_eventHandle = NULL;
	_executeThread = false;
	_asyncWaitThread = nullptr;
	_eventHandle = ::CreateEvent(NULL, false, false, wideName);
}
// Class destructor.
SignaledObjectEvent::~SignaledObjectEvent()
{
	if (!Disposed)
	{
		if (_asyncWaitThread != nullptr)
		{
			StopThread();
			delete(_asyncWaitThread);
		}

		if (_eventHandle != NULL)
			CloseHandle(_eventHandle);
	}
	_asyncWaitThread = nullptr;
	_eventHandle = NULL;
}
// Dispose.
SignaledObjectEvent::!SignaledObjectEvent()
{
	StopThread();
	_asyncWaitThread = nullptr;
	_eventHandle = NULL;
}
#pragma endregion

/*--------------------------------------------------------------------------------
 * Public Properties
 *------------------------------------------------------------------------------*/
#pragma region Public Properties
IntPtr SignaledObjectEvent::EventHandle::get()
{
	if (_eventHandle == NULL)
		return IntPtr::Zero;
	else
		return IntPtr::IntPtr(_eventHandle);
}

bool SignaledObjectEvent::IsWaiting::get()
{
	return ((_asyncWaitThread != nullptr) && (_asyncWaitThread->IsAlive));
}
#pragma endregion

/*--------------------------------------------------------------------------------
 * Protected Methods / Event Methods
 *------------------------------------------------------------------------------*/
#pragma region Protected Methods / Event Methods
void SignaledObjectEvent::OnEventOccurred(EventArgs^ e)
{
	EventOccurred(this, e);
}
bool SignaledObjectEvent::IsEventReady()
{
	return false;
}
#pragma endregion

/*--------------------------------------------------------------------------------
 * Public Methods / Event Methods
 *------------------------------------------------------------------------------*/
#pragma region Public Methods / Event Methods
void SignaledObjectEvent::AsyncWait()
{
	if (_asyncWaitThread == nullptr)
	{
		_asyncWaitThread = gcnew Thread(gcnew ThreadStart(this, &SignaledObjectEvent::RunAsyncWaitThread));
		_asyncWaitThread->IsBackground = true;
		_asyncWaitThread->Start();
	}
}
void SignaledObjectEvent::Clear()
{
	if (_asyncWaitThread != nullptr)
	{
		_asyncWaitThread->Abort();
		delete(_asyncWaitThread);
		_asyncWaitThread = nullptr;
	}

	if (_eventHandle != NULL)
		CloseHandle(_eventHandle);
	_eventHandle = ::CreateEvent(NULL, false, false, NULL);

}
void SignaledObjectEvent::ResetEventStatus()
{
	::ResetEvent(_eventHandle);
}
void SignaledObjectEvent::SignalEvent()
{
	::SetEvent(_eventHandle);
}
void SignaledObjectEvent::WaitForEvent()
{
	DWORD result = 0;

	result = ::WaitForSingleObject(_eventHandle, INFINITE);
	if (result == WAIT_OBJECT_0)
	{
		OnEventOccurred(EventArgs::Empty);
		::ResetEvent(_eventHandle);
	}
}
void SignaledObjectEvent::WaitForEvent(int milliseconds)
{
	DWORD result = 0;

	result = ::WaitForSingleObject(_eventHandle, (DWORD)milliseconds);
	if (result == WAIT_OBJECT_0)
	{
		OnEventOccurred(EventArgs::Empty);
		::ResetEvent(_eventHandle);
	}
}
void SignaledObjectEvent::Sleep(int milliseconds)
{
	HANDLE eventHandle = NULL;

	eventHandle = ::CreateEvent(NULL, true, false, NULL);
	::WaitForSingleObject(eventHandle, (DWORD)milliseconds);
	::CloseHandle(eventHandle);
}
void SignaledObjectEvent::StopThread()
{
	clock_t start = 0;
	clock_t end = 0;

	if ((_asyncWaitThread != nullptr) && (_asyncWaitThread->IsAlive))
	{
		start = clock();
		end = clock();
		_executeThread = false;
		while ((_asyncWaitThread->IsAlive) && (end-start < 3000))
		{
			end = clock();
			Sleep(10);
		}

		if ((_asyncWaitThread != nullptr) && (_asyncWaitThread->IsAlive))
		{
			try
			{
				_asyncWaitThread->Abort();
			}
			catch(...)
			{
			}
			_asyncWaitThread=nullptr;
		}
	}
}
void SignaledObjectEvent::RunAsyncWaitThread()
{
	DWORD result = 0;

	_executeThread = true;
	do
	{
		result = ::WaitForSingleObject(_eventHandle, 20);
		if ((result == WAIT_OBJECT_0) || (IsEventReady()))
		{
			OnEventOccurred(EventArgs::Empty);
			::ResetEvent(_eventHandle);
		}
	} while (_executeThread);
}
#pragma endregion
